package controllers;

import java.lang.reflect.InvocationTargetException;

import models.usuario.Usuario;

import controllers.Seguranca.Security;
import play.cache.Cache;
import play.data.validation.Required;
import play.libs.Crypto;
import play.mvc.*;
import play.mvc.Http.Response;
import play.utils.Java;

public class SegurancaDesktop extends Controller {
	
	//private static String user;
	 @Before(unless={"authenticate", "logout"})
	    static void checkAccess() throws Throwable {
	        // Authent
		 	/*
		 	if(request.cookies.get("usuarioDesktop")==null)
		 		authenticate("", "", false);
		 */
		 	if(!session.contains("usuarioDesktop"))
		 		authenticate("", "", false);
	        
	     // Checks
	        Checar check = getActionAnnotation(Checar.class);
	        if(check != null) {
	            check(check);
	        }
	        check = getControllerInheritedAnnotation(Checar.class);
	        if(check != null) {
	            check(check);
	        }
	        
	    }

	    private static void check(Checar check) throws Throwable {
	        for(String profile : check.value()) {
	            boolean hasProfile = (Boolean)Security.invoke("check", profile);
	            if(!hasProfile) {
	                Security.invoke("onCheckFailed", profile);
	            }
	        }
	    }

	    
	    public static void authenticate(@Required String username, String password, boolean remember) throws Throwable {
	    	
	    	String confirmar;
	    	//Autenticação no desktop só pode ser feita por adminstrador
	    	if(!username.equals("")){
		    	Usuario us = Usuario.find("byEmail", username).first();
		        if(!us.isAdmin){
		        	confirmar = "Usuário não autorizado";
		        	render(confirmar);
		        }
		        
	    	}
	        // Check tokens
	        Boolean allowed = false;
	        try {
	            // This is the deprecated method name
	            allowed = (Boolean)Security.invoke("authentify", username, password);
	        } catch (UnsupportedOperationException e ) {
	            // This is the official method name
	            allowed = (Boolean)Security.invoke("authenticate", username, password);
	        }
	        if(validation.hasErrors() || !allowed) {
	            confirmar="Negado";
	            render(confirmar);
	            
	        }
	        
	        // Mark user as connected
	        session.put("usuarioDesktop", username);
	       // user = username;
	       // Cache.set(session.getId(), username, "30mn");
	       // response.setCookie("usuarioDesktop",username,"1h");
	        confirmar = "Permitido";
	        render(confirmar);
	        
	    }

	    public static void logout() throws Throwable {
	        Security.invoke("onDisconnect");
	        session.clear();
	        //Cache.delete(user);
	       // response.removeCookie("usuarioDesktop");
	        Security.invoke("onDisconnected");
	    }

	    // ~~~ Utils



	    public static class Security extends Controller {

	        /**
	         * @Deprecated
	         * 
	         * @param username
	         * @param password
	         * @return
	         */
	        static boolean authentify(String username, String password) {
	            throw new UnsupportedOperationException();
	        }

	        /**
	         * This method is called during the authentication process. This is where you check if
	         * the user is allowed to log in into the system. This is the actual authentication process
	         * against a third party system (most of the time a DB).
	         *
	         * @param username
	         * @param password
	         * @return true if the authentication process succeeded
	         */

	    	static boolean authenticate(String user_name, String password) {
	            return Application.conectar(user_name, password) != null;
	        }

	        /**
	         * This method checks that a profile is allowed to view this page/method. This method is called prior
	         * to the method's controller annotated with the @Check method. 
	         *
	         * @param profile
	         * @return true if you are allowed to execute this controller method.
	         */
	        static boolean check(String profile) {
	        	if("admin".equals(profile)) {
	                return Usuario.find("byEmail", connected()).<Usuario>first().isAdmin;
	            }
	            return false;
	        }

	        /**
	         * This method returns the current connected username
	         * @return
	         */
	        static String connected() {
	           return session.get("usuarioDesktop");
	        	//return (String) Cache.get(user);
	        	//return request.cookies.get("usuarioDesktop").value;
	        }

	        /**
	         * Indicate if a user is currently connected
	         * @return  true if the user is connected
	         */
	        static boolean isConnected() {
	            //return request.cookies.containsKey("usuarioDesktop");
	        	return session.contains("usuarioDesktop");
	            //return Cache.get(user)!=null;
	        }

	        /**
	         * This method is called after a successful authentication.
	         * You need to override this method if you with to perform specific actions (eg. Record the time the user signed in)
	         */
	        static void onAuthenticated() {
	        }

	         /**
	         * This method is called before a user tries to sign off.
	         * You need to override this method if you wish to perform specific actions (eg. Record the name of the user who signed off)
	         */
	        static void onDisconnect() {
	        }

	         /**
	         * This method is called after a successful sign off.
	         * You need to override this method if you wish to perform specific actions (eg. Record the time the user signed off)
	         */
	        static void onDisconnected() {
	        }

	        /**
	         * This method is called if a check does not succeed. By default it shows the not allowed page (the controller forbidden method).
	         * @param profile
	         */
	        static void onCheckFailed(String profile) {
	            forbidden();
	        }

	        protected static Object invoke(String m, Object... args) throws Throwable {

	            try {
	                return Java.invokeChildOrStatic(Security.class, m, args);       
	            } catch(InvocationTargetException e) {
	                throw e.getTargetException();
	            }
	        }

	    }


}
